package com.xw.musicplayer;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationChannelGroup;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.RemoteViews;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.app.NotificationCompat;

import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.NotificationTarget;
import com.xw.musicplayer.bean.Music;
import com.xw.musicplayer.focus.AudioFocusHelper;
import com.xw.musicplayer.listener.IOnBufferingListener;
import com.xw.musicplayer.listener.IOnMusicChangeListener;
import com.xw.musicplayer.listener.IOnStatusChangeListener;
import com.xw.musicplayer.listener.IOnStopServiceListener;
import com.xw.musicplayer.listener.OnBufferingListener;
import com.xw.musicplayer.listener.OnMusicChangeListener;
import com.xw.musicplayer.listener.OnStatusChangeListener;
import com.xw.musicplayer.utils.PlayStatus;

import java.util.List;

public class MusicServer extends Service implements
        AudioManager.OnAudioFocusChangeListener,
        OnStatusChangeListener,
        OnMusicChangeListener,
        OnBufferingListener {

    private static final int MUSIC_NOTIFY_PLAYER_ID = 11;
    private static final String GROUP_ID = "music_group";
    private static final String GROUP_NAME = "播放组";
    private static final String CHANNEL_ID = "music_channel";
    private static final String CHANNEL_NAME = "播放控制";

    private String mActionPlay = ".play";
    private String mActionPause = ".pause";
    private String mActionPrevious = ".previous";
    private String mActionNext = ".next";
    private String mActionClose = ".close";

    private AudioFocusHelper mAudioFocusHelper;
    private int mLastFocusStatus;

    private ActionReceiver actionReceiver;

    private PlayController mPlayController;
    private RemoteViews mSimpleContentView;
    private RemoteViews mExpandedView;
    private NotificationManager mManager;
    private Handler mMainHandler;
    private BridgeImp mBinder;

    private RemoteCallbackList<IOnStopServiceListener> mStopListenerList = new RemoteCallbackList<>();
    private RemoteCallbackList<IOnStatusChangeListener> mStatusChangeListenerList = new RemoteCallbackList<>();
    private RemoteCallbackList<IOnBufferingListener> mBufferingListenerList = new RemoteCallbackList<>();
    private RemoteCallbackList<IOnMusicChangeListener> mMusicChangeListenerList = new RemoteCallbackList<>();

    @Override
    public void onCreate() {
        super.onCreate();

        mAudioFocusHelper = new AudioFocusHelper(getApplicationContext(), this);
        mMainHandler = new Handler(getMainLooper());
        initReceiver();

        mManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        mPlayController = new PlayController();
        mPlayController.init(getApplicationContext());
        mPlayController.registerStatusChangeListener(this);
        mPlayController.registerMusicChangeListener(this);
        mPlayController.registerBuffingListener(this);

        createNotification();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return super.onStartCommand(intent, flags, startId);
    }

    private void initReceiver() {
        String packageName = getPackageName();
        actionReceiver = new ActionReceiver();

        mActionPlay = packageName + mActionPlay;
        mActionPause = packageName + mActionPause;
        mActionPrevious = packageName + mActionPrevious;
        mActionNext = packageName + mActionNext;
        mActionClose = packageName + mActionClose;

        IntentFilter filter = new IntentFilter();
        filter.addAction(mActionPlay);
        filter.addAction(mActionPause);
        filter.addAction(mActionPrevious);
        filter.addAction(mActionNext);
        filter.addAction(mActionClose);

        registerReceiver(actionReceiver, filter);
    }

    @RequiresApi(api = Build.VERSION_CODES.O)
    private void createNotificationChannel() {

        NotificationChannelGroup group = new NotificationChannelGroup(GROUP_ID, GROUP_NAME);
        mManager.createNotificationChannelGroup(group);

        NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME,
                NotificationManager.IMPORTANCE_LOW);
        channel.setGroup(GROUP_ID);
        //在锁屏页显示全部内容
        channel.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
        mManager.createNotificationChannel(channel);
    }


    private void createNotification() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            createNotificationChannel();
        }

        if (mSimpleContentView == null) {
            mSimpleContentView = new RemoteViews(getPackageName(), R.layout.music_notify_player_small);
            setListener(mSimpleContentView);
        }

        if (mExpandedView == null) {
            mExpandedView = new RemoteViews(getPackageName(), R.layout.music_notify_player_big);
            setListener(mExpandedView);
        }

        boolean isPaused = mPlayController == null || !mPlayController.isPlaying();
        Music music = mPlayController != null ? mPlayController.getCurrent() : null;
        String singer = "";
        String title = "";
        String imagePath = "";

        if (music != null) {
            singer = music.singer;
            title = music.title;
            imagePath = music.iamgePath;
        }

        mSimpleContentView.setViewVisibility(R.id.player_progress_bar, View.GONE);
        mSimpleContentView.setViewVisibility(R.id.player_next, View.VISIBLE);
        mSimpleContentView.setViewVisibility(R.id.player_previous, View.VISIBLE);
        mSimpleContentView.setViewVisibility(R.id.player_pause, isPaused ? View.GONE : View.VISIBLE);
        mSimpleContentView.setViewVisibility(R.id.player_play, isPaused ? View.VISIBLE : View.GONE);
        mSimpleContentView.setTextViewText(R.id.player_song_name, title);
        mSimpleContentView.setTextViewText(R.id.player_author_name, singer);

        mExpandedView.setViewVisibility(R.id.image_next, View.VISIBLE);
        mExpandedView.setViewVisibility(R.id.image_last, View.VISIBLE);
        mExpandedView.setViewVisibility(R.id.player_progress_bar, View.GONE);
        mExpandedView.setViewVisibility(R.id.player_pause, isPaused ? View.GONE : View.VISIBLE);
        mExpandedView.setViewVisibility(R.id.player_play, isPaused ? View.VISIBLE : View.GONE);
        mExpandedView.setTextViewText(R.id.player_song_name, title);
        mExpandedView.setTextViewText(R.id.player_author_name, singer);

        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle(title)
                .setCustomBigContentView(mExpandedView)
                .setContent(mSimpleContentView)
                .setSmallIcon(R.mipmap.float_music_icon)
                .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
                .build();

        notification.flags |= Notification.FLAG_ONGOING_EVENT;
        loadImage(imagePath, notification);
        startForeground(MUSIC_NOTIFY_PLAYER_ID, notification);
    }

    private void loadImage(String imagePath, Notification notification) {
        mMainHandler.post(() -> {
            NotificationTarget expandedTarget = new NotificationTarget(this,
                    R.id.player_album_art, mExpandedView, notification, MUSIC_NOTIFY_PLAYER_ID);

            NotificationTarget simpleTarget = new NotificationTarget(this,
                    R.id.player_album_art, mSimpleContentView, notification, MUSIC_NOTIFY_PLAYER_ID);

            if (!TextUtils.isEmpty(imagePath)) {
                Glide.with(this)
                        .asBitmap()
                        .load(imagePath)
                        .into(expandedTarget);

                Glide.with(this)
                        .asBitmap()
                        .load(imagePath)
                        .into(simpleTarget);
            } else {
                Glide.with(this)
                        .asBitmap()
                        .load(R.mipmap.float_music_icon)
                        .into(expandedTarget);

                Glide.with(this)
                        .asBitmap()
                        .load(R.mipmap.float_music_icon)
                        .into(simpleTarget);
            }
        });
    }

    private void setListener(RemoteViews view) {
        try {
            PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
                    0, new Intent(mActionPrevious).setPackage(getPackageName()),
                    PendingIntent.FLAG_UPDATE_CURRENT);
            view.setOnClickPendingIntent(R.id.player_previous, pendingIntent);

            pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
                    0, new Intent(mActionClose).setPackage(getPackageName()),
                    PendingIntent.FLAG_UPDATE_CURRENT);
            view.setOnClickPendingIntent(R.id.player_close, pendingIntent);

            pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
                    0, new Intent(mActionPause).setPackage(getPackageName()),
                    PendingIntent.FLAG_UPDATE_CURRENT);
            view.setOnClickPendingIntent(R.id.player_pause, pendingIntent);

            pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
                    0, new Intent(mActionNext).setPackage(getPackageName()),
                    PendingIntent.FLAG_UPDATE_CURRENT);
            view.setOnClickPendingIntent(R.id.player_next, pendingIntent);

            pendingIntent = PendingIntent.getBroadcast(getApplicationContext(),
                    0, new Intent(mActionPlay).setPackage(getPackageName()),
                    PendingIntent.FLAG_UPDATE_CURRENT);
            view.setOnClickPendingIntent(R.id.player_play, pendingIntent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        mAudioFocusHelper.abandon();
        if (actionReceiver != null) {
            unregisterReceiver(actionReceiver);
        }

        if (mPlayController != null) {
            mPlayController.destroy();
            mPlayController = null;
        }
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        if (mBinder == null) {
            mBinder = new BridgeImp();
        }
        return mBinder;
    }

    @Override
    public void onAudioFocusChange(int focusChange) {
        Log.d("info", "=====焦点问题===" + focusChange);
        switch (focusChange) {
            //短暂失去焦点
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
                //永久性失去焦点
            case AudioManager.AUDIOFOCUS_LOSS:
                if (mPlayController != null) {
                    mPlayController.pause();
                }
                break;

            //重新获得了焦点
            case AudioManager.AUDIOFOCUS_GAIN:
                if (mLastFocusStatus == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT) {
                    //上一次是短暂性失去焦点则需要继续播放
                    playInner();
                }
                break;

            //降低音量的短暂短暂性失去焦点
            case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
                break;

            default:
                break;
        }

        mLastFocusStatus = focusChange;
    }

    private void playInner() {
        if (mPlayController != null) {
            mAudioFocusHelper.request(this);
            mPlayController.play();
        }
    }

    /**
     * 非焦点变化引起的暂停.
     */
    private void pauseInner() {
        if (mPlayController != null) {
            mPlayController.pause();
        }

        if (mAudioFocusHelper != null) {
            mAudioFocusHelper.abandon();
        }
    }

    @Override
    public void onStatusChange(int status) {
        if (status != PlayStatus.STATE_RELEASE) {
            createNotification();
        }

        int count = mStatusChangeListenerList.beginBroadcast();
        for (int i = 0; i < count; i++) {
            IOnStatusChangeListener listener = mStatusChangeListenerList.getBroadcastItem(i);
            if (listener != null) {
                try {
                    listener.onStatusChange(status);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        mStatusChangeListenerList.finishBroadcast();
    }

    @Override
    public void onMusicChange(int newPosition, int oldPosition) {
        int count = mMusicChangeListenerList.beginBroadcast();
        for (int i = 0; i < count; i++) {
            IOnMusicChangeListener listener = mMusicChangeListenerList.getBroadcastItem(i);
            if (listener != null) {
                try {
                    listener.onMusicChange(newPosition, oldPosition);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
        mMusicChangeListenerList.finishBroadcast();
    }

    @Override
    public void onBufferingStart() {
        int count = mBufferingListenerList.beginBroadcast();
        for (int i = 0; i < count; i++) {
            IOnBufferingListener listener = mBufferingListenerList.getBroadcastItem(i);
            if (listener != null) {
                try {
                    listener.onBufferingStart();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }

        mBufferingListenerList.finishBroadcast();
    }

    @Override
    public void onBufferingEnd() {
        int count = mBufferingListenerList.beginBroadcast();
        for (int i = 0; i < count; i++) {
            IOnBufferingListener listener = mBufferingListenerList.getBroadcastItem(i);
            if (listener != null) {
                try {
                    listener.onBufferingEnd();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
        mBufferingListenerList.finishBroadcast();
    }

    private class ActionReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();

            if (TextUtils.isEmpty(action)) {
                return;
            }

            if (TextUtils.equals(action, mActionPlay)) {
                playInner();
            } else if (TextUtils.equals(action, mActionPause)) {
                pauseInner();
            } else if (TextUtils.equals(action, mActionPrevious)) {
                mPlayController.playPrevois();
            } else if (TextUtils.equals(action, mActionNext)) {
                mPlayController.playNext();
            } else if (TextUtils.equals(action, mActionClose)) {
                int count = mStopListenerList.beginBroadcast();
                if (count <= 0) {
                    //不存在连接了,就关闭自己
                    stopSelf();
                } else {
                    for (int i = 0; i < count; i++) {
                        IOnStopServiceListener listener = mStopListenerList.getBroadcastItem(i);
                        if (listener != null) {
                            try {
                                listener.onStopService();
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                    mStopListenerList.finishBroadcast();
                }
                MusicPlayer.getInstance().removeFloatWindow();

            }
        }
    }

    private class BridgeImp extends IMusicPlayerBridge.Stub {

        @Override
        public void setMusicList(String listId, List<Music> musics) throws RemoteException {
            if (mPlayController != null && musics != null && !musics.isEmpty()) {
                mPlayController.setmMusicList(listId,musics);
                createNotification();
            }
        }

        @Override
        public List<Music> getMusicList() throws RemoteException {
            if (mPlayController != null) {
                return mPlayController.getMusicList();
            }
            return null;
        }

        @Override
        public Music getMusic(int position) throws RemoteException {
            if (mPlayController != null) {
                return mPlayController.getMusic(position);
            }
            return null;
        }

        @Override
        public String getMusicListId() throws RemoteException {
            if (mPlayController != null) {
                return mPlayController.getMusicListId();
            }
            return null;
        }

        @Override
        public int getPlayingIndex() throws RemoteException {
            if (mPlayController != null) {
                return mPlayController.getPlayIndex();
            }
            return 0;
        }

        @Override
        public int getMusicCount() throws RemoteException {
            if (mPlayController != null) {
                return mPlayController.getMusicCount();
            }
            return -1;
        }

        @Override
        public void play() throws RemoteException {
            playInner();
        }

        @Override
        public void playIndex(int position) throws RemoteException {
            if (mPlayController != null) {
                mPlayController.playIndex(position);
            }
        }

        @Override
        public void playNext() throws RemoteException {
            if (mPlayController != null) {
                mPlayController.playNext();
            }
        }

        @Override
        public void playPrevious() throws RemoteException {
            if (mPlayController != null) {
                mPlayController.playPrevois();
            }
        }

        @Override
        public void pause() throws RemoteException {
            if (mPlayController != null) {
                pauseInner();
            }
        }

        @Override
        public void reset() throws RemoteException {
            if (mPlayController != null) {
                mPlayController.reset();
            }
        }

        @Override
        public void setSeek(int milliseconds) throws RemoteException {
            if (mPlayController != null) {
                mPlayController.setSeek(milliseconds);
            }
        }

        @Override
        public long getCurrentPosition() throws RemoteException {
            if (mPlayController != null) {
                return mPlayController.getCurrentPosition();
            }
            return -1;
        }

        @Override
        public long getDuration() throws RemoteException {
            if (mPlayController != null) {
                return mPlayController.getDuration();
            }
            return -1;
        }

        @Override
        public int getBufferedPercentage() throws RemoteException {
            if (mPlayController != null) {
                return mPlayController.getBufferedPercentage();
            }
            return -1;
        }

        @Override
        public boolean isPlaying() throws RemoteException {
            if (mPlayController != null) {
                return mPlayController.isPlaying();
            }
            return false;
        }

        @Override
        public void registerOnStopListener(IOnStopServiceListener listener) throws RemoteException {
            mStopListenerList.register(listener);
        }

        @Override
        public void unregisterOnStopListener(IOnStopServiceListener listener) throws RemoteException {
            mStopListenerList.unregister(listener);
        }

        @Override
        public void registerOnMusicChangeListener(IOnMusicChangeListener listener) throws RemoteException {
            mMusicChangeListenerList.register(listener);
        }

        @Override
        public void unregisterOnMusicChangeListener(IOnMusicChangeListener listener) throws RemoteException {
            mMusicChangeListenerList.unregister(listener);
        }

        @Override
        public void registerOnBufferingListener(IOnBufferingListener listener) throws RemoteException {
            mBufferingListenerList.register(listener);
        }

        @Override
        public void unregisterOnBufferingListener(IOnBufferingListener listener) throws RemoteException {
            mBufferingListenerList.unregister(listener);
        }

        @Override
        public void registerOnStatusChangeListener(IOnStatusChangeListener listener) throws RemoteException {
            mStatusChangeListenerList.register(listener);
        }

        @Override
        public void unregisterOnStatusChangeListener(IOnStatusChangeListener listener) throws RemoteException {
            mStatusChangeListenerList.unregister(listener);
        }

        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            //覆写该方法,定位问题aidl里面的问题
            try {
                return super.onTransact(code, data, reply, flags);
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            }
        }
    }
}
